import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

# 加载数据
data = pd.read_csv('./boston.csv')

# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300

# 对CRIM进行对数转换
data['log_CRIM'] = np.log(data['CRIM'])

# 将对数转换后的CRIM分5级
data['CRIM_level'] = pd.qcut(data['log_CRIM'], q=5, labels=False)

# 创建一个新的图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制左右镜像的小提琴图
sns.violinplot(x='CRIM_level', y='log_CRIM', data=data, inner='box', split=True, ax=ax, palette='Blues_d', saturation=0.5)
sns.violinplot(x='CRIM_level', y='MEDV', data=data, inner='box', split=True, ax=ax, palette='Reds_d', saturation=0.5)

# 内嵌均值点
for i, level in enumerate(data['CRIM_level'].unique()):
    level_data_log_crim = data[data['CRIM_level'] == level]['log_CRIM']
    level_data_medv = data[data['CRIM_level'] == level]['MEDV']
    ax.scatter(i - 0.25, level_data_log_crim.mean(), marker='o', color='blue', zorder=3)
    ax.scatter(i + 0.25, level_data_medv.mean(), marker='o', color='red', zorder=3)

# 使颜色饱和度随犯罪率等级增加
for i, violin in enumerate(ax.collections[::2]):
    violin.set_facecolor(plt.cm.Blues((i + 1) / 5))
for i, violin in enumerate(ax.collections[1::2]):
    violin.set_facecolor(plt.cm.Reds((i + 1) / 5))

# 添加核密度曲线说明文字
ax.text(-0.5, -2, '犯罪率分布 (对数转换)', color='blue', rotation=30, va='center', size=8)
ax.text(-0.5, 50, '房价分布', color='red', rotation=50, va='center', size=8)


# 设置标题和坐标轴标签
ax.set_title('不同犯罪率区间的房价分布形态')
ax.set_xlabel('犯罪率等级')
ax.set_ylabel('数值')

# 显示图形
plt.show()